﻿using System;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using Org.Flowertwig.Media.Information;
using Org.Flowertwig.Media.Information.Interfaces;
using Org.Flowertwig.Media.Information.MediaIdentifiers;
using Org.Flowertwig.Media.Information.Services;
using Org.Flowertwig.Media.Services.InformationService.Sources;
using Raven.Client.Indexes;

namespace Org.Flowertwig.Media.Services.InfoService
{
    public class InfoCollector : ISource
    {
        protected Thread _thread;
        private static string SpecialDirSample = Path.DirectorySeparatorChar + "Sample";
        private static string SpecialDirSubs = Path.DirectorySeparatorChar + "Subs";

        static Regex _serieRegExp = new Regex(@".*\\(?<Name>[a-zA-Z0-9\.\ \'\-]+)[\.|\ ][S|s]{0,1}(?<Season>[0-9]{1,2})[E|e|X|x](?<Episode>[0-9]{0,2}).*[\\|.].*", RegexOptions.Compiled);

        public static Service ServiceKey
        {
            get
            {
                return new Service
                           {
                               Id = "LS",
                               Name = "LocalService",
                               ApplicationPathAndName = typeof(InfoCollector).Assembly.Location
                           };
            }
        }

        public InfoCollector()
        {
            Console.WriteLine("InfoCollector Service");
            _thread = new Thread(OnStart);
        }

        public void Start()
        {
            Console.WriteLine("# Starting");
            _thread.Start();
        }

        protected void OnStart()
        {
            EnsureIndexes();


            bool hasMedia;
            Console.WriteLine("# Medias");

            int startIndex = 0;
            int length = 128;

            do
            {
                hasMedia = false;

                Console.WriteLine("# Retreiving more Media");

                var mediaWithNoInformationId = Storage.GetDocumentsForIndex<Information.Media>("GetMediaWithNoInformationId", startIndex, length);

                foreach (var media in mediaWithNoInformationId)
                {
                    // As our index is not always up to date we need to check the values for the result
                    if (!string.IsNullOrEmpty(media.InformationId))
                        continue;

                    hasMedia = true;

                    IIdentifierInfo identifierInfo;
                    if (SerieIdentifier.TryIdentify(media, out identifierInfo))
                    {
                        // TODO: Check against stored series before doing this. If we have information about serie, why ask about it again?
                        var serie = TvRage.GetSerie(identifierInfo.SearchWord);
                        if (serie != null)
                        {
                            Storage.AddSerie(serie);
                            Console.WriteLine(string.Format("S\t{0}\t- {1}", serie.Name, media.Name));

                            string id = SerieIdentifier.GetInformationId(serie, identifierInfo);
                            if (!string.IsNullOrEmpty(id))
                            {
                                media.InformationId = id;

                                Storage.UpdateMedia(media);
                            }
                        }
                    }
                    else
                    {
                        Movie movie = TheMoveDbSoruce.GetMovie(media.Name);
                        if (movie != null)
                        {


                            Console.WriteLine(string.Format("M\t{0}\t- {1}", movie.Name, media.Name));
                        }
                        else
                        {


                            // we want to ignore files we couldnt identify in the next run.
                            startIndex++;

                            Console.WriteLine(string.Format("-\t{0}", media.Name));
                        }
                    }
                }

                // TODO: We should just refresh the selection for the index here instead
                Console.WriteLine("# Waiting 1 min for the index to be updated");
                Thread.Sleep( 60 * 1000);
            } while (hasMedia);
        }

        private void EnsureIndexes()
        {
            if (!Storage.HasIndex("GetMediaWithNoInformationId"))
            {
                CreateIndexForMediaWithNoInformationId();
            }
        }

        private void CreateIndexForMediaWithNoInformationId()
        {
            Storage.AddIndex<Information.Media>("GetMediaWithNoInformationId",
                                      new IndexDefinitionBuilder<Information.Media>
                                          {
                                              Map =
                                                  medias =>
                                                  from media in medias
                                                  where media.InformationId == null
                                                  select new
                                                             {
                                                                 Name =
                                                      media.Name,
                                                                 Added =
                                                      media.Added,
                                                                 Id =
                                                      media.Id,
                                                                 InformationId
                                                      =
                                                      media.InformationId,
                                                                 InternalServiceId
                                                      =
                                                      media.
                                                      InternalServiceId,
                                                                 QualityName =
                                                      media.QualityName,
                                                                 ReleaserName
                                                      =
                                                      media.ReleaserName,
                                                                 RequireProcessBeforePlay
                                                      =
                                                      media.
                                                      RequireProcessBeforePlay,
                                                                 ServiceId =
                                                      media.ServiceId
                                                             }

                                          });
        }

        public void Stop()
        {
            if (_thread != null)
            {
                //Console.WriteLine("Stopping server.");
                _thread.Abort();
            }
        }
    }
}
